#include <QDebug>
#include "faceobject.h"

std::unique_ptr<FaceObject> FaceObject::m_instance_;  // 类外初始化单例

FaceObject *FaceObject::getInstance() {
    if (m_instance_ == nullptr) {  // 创建单例，由于QT程序默认是单线程的，因此此处不必担心线程安全问题
        m_instance_.reset(new FaceObject());
        m_instance_->initEngine();
    }
    return m_instance_.get();
}

void FaceObject::initEngine() {
    // 引入预训练的模型文件来创建人脸检测引擎，用于人脸检测/识别和关键点定位
    seeta::ModelSetting FDmodel("D:/SeetaFace2/build/InstallPerf/bin/model/fd_2_00.dat", seeta::ModelSetting::CPU, 0);
    seeta::ModelSetting PDmodel("D:/SeetaFace2/build/InstallPerf/bin/model/pd_2_00_pts5.dat", seeta::ModelSetting::CPU, 0);
    seeta::ModelSetting FRmodel("D:/SeetaFace2/build/InstallPerf/bin/model/fr_2_10.dat", seeta::ModelSetting::CPU, 0);
    // FaceEngine是SeetaFace2库的核心类，封装了人脸检测，关键点定位和人脸识别等功能
    pfe_ = std::make_unique<seeta::FaceEngine>(FDmodel, PDmodel, FRmodel);
    pfe_->Load("face.db");    // 导入已有人脸库，用于后续人脸判重
}

int64_t FaceObject::faceRegister(cv::Mat &fdata) {
    // 将opencv的Mat数据转为seetaface图像类型数据
    SeetaImageData simg;
    simg.data = fdata.data;
    simg.width = fdata.cols;
    simg.height = fdata.rows;
    simg.channels = fdata.channels();
    // 检查当前人脸是否已注册过
    float similarity = 0;
    pfe_->Query(simg, &similarity);
    if (similarity > 0.7) {  // 相似度大于75%时认为是同一张脸
        qDebug() << "FaceObject::faceRegister(): 已注册过相同人脸！\n";
        return -1;
    }
    // 注册并返回注册的ID
    auto fid = pfe_->Register(simg);
    if (fid >= 0) {              // 不为负数说明注册成功
        pfe_->Save("face.db");  // 在face.db下保存所有人脸ID信息
    } else {
        qDebug() << "seeta::FaceEngine::Register(): 函数执行失败！\n";
    }
    return fid;
}

void FaceObject::faceQuery(cv::Mat &fdata) {
    // 将opencv的Mat数据转为seetaface图像类型数据
    SeetaImageData simg;
    simg.data = fdata.data;
    simg.width = fdata.cols;
    simg.height = fdata.rows;
    simg.channels = fdata.channels();
    // 查询，返回-1为未查询到
    float similarity = 0;  // 相似度
    auto face_id = pfe_->Query(simg, &similarity);       // 性能瓶颈
    emit sendFaceID(similarity > 0.7 ? face_id : -1);   // 相似度判定同上
}

bool FaceObject::detectFace(cv::Mat &fdata) {
    if (fdata.empty()) {
        qDebug() << "FaceObject::detectFace(): 图像为空";
        return false;
    }
    cv::Mat gfdata;
    cv::cvtColor(fdata, gfdata, cv::COLOR_BGR2GRAY);  // 将原始帧转成灰度图以加快检测速度
    SeetaImageData simg;                         // 生成seetaface类型的图像数据
    simg.data = gfdata.data;
    simg.width = gfdata.cols;
    simg.height = gfdata.rows;
    simg.channels = gfdata.channels();
    return !pfe_->DetectFaces(simg).empty();
}

void FaceObject::deleteFace(int64_t face_id) {
    // 删除人脸库中对应face_id的人脸信息
    pfe_->Delete(face_id);
    pfe_->Save("face.db");  // 不要忘记保存
}
